Tuesday, December 13, 2016

Heap's Algorithm and Generating Perl Code From Pseudocode

I've been researching recursion lately and in particular, permutations algorithms. This interest was spurred by a real-life case where such an algorithm would come in handy (combinations of @clients, @users, @tickets). I came across Wikipedia's entry for Heap's algorithm and the pseudocode illustrating the algorithm. I found the non-recursive version even more interesting specifically for its lack of needing to call itself, so I chose that version of the algorithm to study.

I thought it would be an interesting exercise to convert the pseudocode to Perl code. While I was converting it I was struck by how closely the Perl code could be made to look like the pseudocode, but also how easy idiomatic Perl made it to skip certain parts of the pseudocode altogether, so I wrote two separate Perl implementations of the algorithm: one to mirror the pseudocode as closely as possible, and one to cut corners using idiomatic Perl.

First, the "pseudocode" version:

  1. sub output {
  2. my (@to_print) = @_;
  3. print join( ',', @to_print ), "\n";
  4. }
  5. sub is_even {
  6. return $_[0] % 2 ? 0 : 1;
  7. }
  8. # By referring to $_[0] and $_[1] instead of assigning their values to other
  9. # variables, we can force pass-by-reference here so that the change will
  10. # impact @A directly even though we are in a separate function outside its
  11. # scope.
  12. sub swap {
  13. ($_[0],$_[1]) = ($_[1],$_[0]);
  14. }
  15. sub generate {
  16. my ($n, @A) = @_;
  17. my @c;
  18. for ( my $i = 0; $i < $n; $i += 1 ) {
  19. $c[$i] = 0;
  20. }
  21. output(@A);
  22. my $i = 0;
  23. while ( $i < $n ) {
  24. if ( $c[$i] < $i ) {
  25. if ( is_even($i) ) {
  26. swap( $A[0], $A[$i] );
  27. }
  28. else {
  29. swap( $A[ $c[$i] ], $A[$i] );
  30. }
  31. output(@A);
  32. $c[$i] += 1;
  33. $i = 0;
  34. }
  35. else {
  36. $c[$i] = 0;
  37. $i += 1;
  38. } # end if
  39. } # end while
  40. }
  41. generate( 3, 'work', 'sleep', 'play' );

Output:

work,sleep,play
sleep,work,play
play,work,sleep
work,play,sleep
sleep,play,work
play,sleep,work

Next, the idiomatic Perl version:

  1. sub output {
  2. print join( ',', @_ ), "\n";
  3. }
  4. sub generate {
  5. # We don't need to pass n here because we have @A. That's not at all
  6. # unique to Perl of course but the cool part comes later...
  7. my (@A) = @_;
  8. # I don't need to specify the length of array @c because as soon as we
  9. # refer to an element, it exists. I don't need to initialize @c or $i
  10. # because as soon as we start performing math on their values they will be
  11. # assumed to start at zero.
  12. my (@c,$i);
  13. output(@A);
  14. # The cool part: we can refer to the length of the @A array as simply @A
  15. # in scalar context.
  16. while ( $i < @A ) {
  17. if ( $c[$i] < $i ) {
  18. # Test for is_odd by seeing if modulo 2 of $i is non-zero.
  19. # Since we check for is_odd vs is_even, we swap the code in the
  20. # if-else.
  21. if ( $i % 2 ) {
  22. # The swap function was handy but idiomatic Perl allows us to
  23. # swap variables in place
  24. ( $A[ $c[$i] ], $A[$i] ) = ( $A[$i], $A[ $c[$i] ] );
  25. }
  26. else {
  27. ( $A[0], $A[$i] ) = ( $A[$i], $A[0] );
  28. }
  29. output(@A);
  30. # Nitpicky but it's nice to have ++ instead of += 1. Again, not
  31. # limited to Perl.
  32. $c[$i]++;
  33. $i = 0;
  34. }
  35. else {
  36. $c[$i] = 0;
  37. $i++;
  38. }
  39. }
  40. }
  41. generate( split '', 'abc' );

Output:

a,b,c
b,a,c
c,a,b
a,c,b
b,c,a
c,b,a

In what ways could the program be further reduced?


EDIT: A change by an anonymous commenter makes this even more compact:

  1. sub output {
  2. print join( ',', @_ ), "\n";
  3. }
  4. sub generate {
  5. my (@A) = @_;
  6. output(@A);
  7. while ( $i < @A ) {
  8. if ( $c[$i] < $i ) {
  9. my $x = $i % 2 ? $c[ $i ] : 0;
  10. ( $A[ $x ], $A[$i] ) = ( $A[$i], $A[ $x ] );
  11. output(@A);
  12. $c[$i]++;
  13. $i = 0;
  14. }
  15. else {
  16. $c[$i] = 0;
  17. $i++;
  18. }
  19. }
  20. }
  21. generate( split '', 'abcd' );

Monday, September 26, 2016

Tattletale Variables

Sometimes you might be faced with a huge program that, somewhere, is changing a variable's value to something undesired.

  1. use Data::Dumper;
  2. sub some_long_faraway_function {
  3. my $href = shift;
  4. # Pretend there's a lot of code here I don't want to sift through
  5. $href->{bananas} = 'some bad value';
  6. }
  7. my $shopping_list = {
  8. apples => 1,
  9. pears => 3,
  10. bananas => 5,
  11. };
  12. some_long_faraway_function($shopping_list);
  13. warn Dumper(\$shopping_list);

Output:

$VAR1 = \{
            'apples' => 1,
            'bananas' => 'some bad value',
            'pears' => 3
        };

You don't know where it's being changed, but you need to find out. Change the variable so that it tells you where it's being changed.

  1. package TattletaleScalar;
  2. use Carp qw(cluck);
  3. require Tie::Scalar;
  4. our @ISA = qw(Tie::StdScalar);
  5. sub STORE {
  6. warn "TATTLETALE variable set to {$_[1]}";
  7. cluck();
  8. ${$_[0]} = $_[1];
  9. }
  10. package main;
  11. use Data::Dumper;
  12. sub some_long_faraway_function {
  13. my $href = shift;
  14. # Pretend there's a lot of code here I don't want to sift through
  15. $href->{bananas} = 'some bad value';
  16. }
  17. my $shopping_list = {
  18. apples => 1,
  19. pears => 3,
  20. bananas => 5,
  21. };
  22. my $tmp = $shopping_list->{bananas}; # Save current value
  23. tie $shopping_list->{bananas}, 'TattletaleScalar';
  24. $shopping_list->{bananas} = $tmp; # Restore saved value
  25. some_long_faraway_function($shopping_list);
  26. warn Dumper(\$shopping_list);

Now we can see the stack every time the variable is changed:

TATTLETALE variable set to {5} at example.pl line 7.
at example.pl line 8.
    TattletaleScalar::STORE(TattletaleScalar=SCALAR(0x7fac290d3260), 5) called at example.pl line 29
TATTLETALE variable set to {some bad value} at example.pl line 7.
at example.pl line 8.
    TattletaleScalar::STORE(TattletaleScalar=SCALAR(0x7fac290d3260), "some bad value") called at example.pl line 19
    main::some_long_faraway_function(HASH(0x7fac29026508)) called at example.pl line 30
$VAR1 = \{
            'apples' => 1,
            'pears' => 3,
            'bananas' => 'some bad value'
        };

Monday, September 12, 2016

Build Your Memory Palace

Earlier this year, I gave a talk, "Building Your Memory Palace." Here are a few notes about the presentation:





Wednesday, August 26, 2015

Using Dispatch Tables To Improve Application Security

Update: I have changed the title to "Using Dispatch Tables To Improve Application Security" for clarity.

At a previous job, I saw some code that asked the user which function they wanted to run and then executed a subroutine with that name. This code demonstrates why such a practice is bad:

  1. use strict;
  2. use warnings;
  3. sub greet { print "Hello!\n" }
  4. sub inquire { print "How are you?\n" }
  5. sub bye { print "Farewell!\n" }
  6. sub delete_all_files { print "*KABOOM*\n" }
  7. sub insecure_call {
  8. no strict 'refs';
  9. shift->();
  10. }
  11. insecure_call('greet');
  12. insecure_call('inquire');
  13. insecure_call('bye');
  14. insecure_call('delete_all_files');

Output:

Hello!
How are you?
Farewell!
*KABOOM*

One solution to this is the dispatch table. With a dispatch table, you define up front which calls are legal for an outsider to make:

  1. use strict;
  2. use warnings;
  3. my %dispatch = (
  4. greet => \&greet,
  5. inquire => \&inquire,
  6. bye => \&bye,
  7. );
  8. sub greet { print "Hello!\n" }
  9. sub inquire { print "How are you?\n" }
  10. sub bye { print "Farewell!\n" }
  11. sub delete_all_files { print "*KABOOM*\n" }
  12. sub secure_call {
  13. my $call = shift;
  14. if ( ref $dispatch{$call} eq 'CODE' ) {
  15. $dispatch{$call}->();
  16. }
  17. else {
  18. warn "Invalid call $call";
  19. }
  20. }
  21. secure_call('greet');
  22. secure_call('inquire');
  23. secure_call('bye');
  24. secure_call('delete_all_files');

Output:

Hello!
How are you?
Farewell!
Invalid call delete_all_files at example_2a line 22.

The thing that bugs me about this particular solution (and I'll admit it's minor) is the repetition:

  1. my %dispatch = (
  2. greet => \&greet,
  3. inquire => \&inquire,
  4. bye => \&bye,
  5. );

To me, this reads like:

To go to greet, type 'greet'.
To go to inquire, type 'inquire'.
To go to bye, type 'bye'.

When it could just be asking "Which function do you wish to use?"

So, we could build the dispatch table dynamically from a list of acceptable calls:

  1. use strict;
  2. use warnings;
  3. my %dispatch;
  4. my @valid_calls = qw( greet inquire bye );
  5. sub greet { print "Hello!\n" }
  6. sub inquire { print "How are you?\n" }
  7. sub bye { print "Farewell!\n" }
  8. sub delete_all_files { print "*KABOOM*\n" }
  9. sub build_dispatch_table {
  10. no strict 'refs';
  11. %dispatch = map { $_ => *{$_} } @valid_calls;
  12. }
  13. sub secure_call {
  14. my $call = shift;
  15. if ( $dispatch{$call} ) {
  16. $dispatch{$call}->();
  17. }
  18. else {
  19. warn "Invalid call $call\n";
  20. }
  21. }
  22. build_dispatch_table();
  23. secure_call('greet');
  24. secure_call('inquire');
  25. secure_call('bye');
  26. secure_call('delete_all_files');
  27. print "\nBut, now this works because of the typeglob *{}\n";
  28. our @greet = qw( This is an array );
  29. print "@{$dispatch{greet}}\n";
  30. print "which annoys me even though it's probably inconsequential\n";

Output:

Hello!
How are you?
Farewell!
Invalid call delete_all_files

But, now this works because of the typeglob *{}
This is an array
which annoys me even though it's probably inconsequential

In addition to the typeglob annoyance, there is still a little repetition there: greet, inquire and bye still appear more than once in the code. I don't actually find this to be a huge deal, but how might we solve those issues? One way is including the code itself in the dispatch table:

  1. use strict;
  2. use warnings;
  3. my %dispatch = (
  4. # Documentation for greet can go here
  5. greet =>
  6. sub {
  7. my $greeting = shift || 'Howdy!';
  8. print "$greeting\n";
  9. },
  10. # Documentation for inquire can go here
  11. inquire =>
  12. sub {
  13. print "How are you?\n";
  14. },
  15. # Documentation for farewell can go here
  16. farewell =>
  17. sub {
  18. print "Bye!\n";
  19. },
  20. );
  21. sub delete_all_files { print "*KABOOM*" }
  22. sub api {
  23. my $call = shift;
  24. if ( $dispatch{$call} ) {
  25. $dispatch{$call}->(@_);
  26. }
  27. else {
  28. warn "Not executing unknown API call $call\n";
  29. }
  30. }
  31. api('greet','Hello.');
  32. api('inquire');
  33. api('farewell');
  34. api('delete_all_files');

Output:

Hello.
How are you?
Bye!
Not executing unknown API call delete_all_files

One argument against this is it adds visual complexity to the code: it's one more layer that a new developer on the project would need to mentally parse before coming up-to-speed on the code. But, that may be minor, and I think these formatting choices are developer-friendly.

Friday, August 07, 2015

Accepting Input from Multiple Sources

One of the corners I often paint myself into when developing a tool is only accepting one type of input, usually STDIN, the standard input stream, like a pipeline (ex: cat fruit.txt | grep apple) or a redirect (ex: grep apple < fruit.txt)

What inevitably happens is I end up wanting the tool to work like any Unix tool and accept different kinds of input (filenames or arguments on the command line, for example.)

Finally I got fed up with it and added a function called multi_input() to my library. Here is how it works:

First, the setup:

$ cat >meats
chicken
beef
^D
$ cat >fruits
apple
orange
banana
^D
$ cat >vegetables
carrot
lettuce
broccoli
cauliflower
^D
$ cat >a.out
this is just my
default input file
^D

To illustrate use of the function, I just reverse the input to do something "interesting" with it. The operative code is:

  1. my $input = multi_input();
  2. my $reversed = reverse $input;
  3. print "$input\n";
  4. print "$reversed\n";

So now I can interact with the tool in a variety of ways, starting with my "usual" way, STDIN:

$ ./reverse.pl < vegetables
current_input_type is: STDIN
carrot
lettuce
broccoli
cauliflower

rewolfiluac
iloccorb
ecuttel
torrac

Or STDIN by way of a pipe (this is the same mechanism in the code, but just to give another example):

$ cat fruits | ./reverse.pl
current_input_type is: STDIN
apple
orange
banana

ananab
egnaro
elppa

Or filenames provided on the command line:

$ ./reverse.pl meats fruits
current_input_type is: FILEARGS
chicken
beef
apple
orange
banana

ananab
egnaro
elppa
feeb
nekcihc

Or input provided on the command line:

$ ./reverse.pl this is not a list of filenames
current_input_type is: ARGS
this is not a list of filenames
semanelif fo tsil a ton si siht

And finally, the ultimate lazy, my default input file a.out:

$ ./reverse.pl
current_input_type is: DEFAULT
this is just my
default input file

elif tupni tluafed
ym tsuj si siht

Here is the full code listing with comments:

  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Term::ReadKey; # for ReadMode() below
  5. sub multi_input {
  6. my $input = '';
  7. my $VERBOSE = 1;
  8. my %INPUT_TYPE = ( # names for self-documenting code
  9. NONE => 0,
  10. ARGS => 1,
  11. FILEARGS => 2,
  12. STDIN => 3,
  13. DEFAULT => 4,
  14. );
  15. my %INPUT_LABEL = reverse %INPUT_TYPE; # allow lookup by number
  16. my $current_input_type = $INPUT_TYPE{NONE};
  17. # I could have done this all in one "shot" but I wanted to keep the
  18. # detection of input type separate from the processing of input
  19. my $char;
  20. if ( @ARGV ) {
  21. # Note that a filename typo will result in processing of the command
  22. # line like it is normal input, but that won't matter in this example.
  23. if ( -f $ARGV[0] ) {
  24. $current_input_type = $INPUT_TYPE{FILEARGS};
  25. }
  26. else {
  27. $current_input_type = $INPUT_TYPE{ARGS};
  28. }
  29. }
  30. else {
  31. # Code from Perl Cookbook. We peek into STDIN stream to see if
  32. # anything's there. The read still counts, though, so we need to save
  33. # $char. perldoc Term::ReadKey for information on ReadMode() and
  34. # ReadKey()
  35. ReadMode('cbreak');
  36. if (defined ($char = ReadKey(-1)) ) {
  37. $current_input_type = $INPUT_TYPE{STDIN};
  38. }
  39. else {
  40. $current_input_type = $INPUT_TYPE{DEFAULT};
  41. }
  42. ReadMode('normal');
  43. }
  44. warn "current_input_type is: $INPUT_LABEL{$current_input_type}\n"
  45. if $VERBOSE;
  46. if ( $current_input_type == $INPUT_TYPE{FILEARGS} ) {
  47. local $/; # Slurp the whole file in at once, not line-by-line
  48. for my $file (@ARGV) {
  49. open(my $ifh, '<', $file) or die "Can't open $file: $!";
  50. $input .= <$ifh>;
  51. close($ifh) || warn "close failed: $!";
  52. }
  53. }
  54. elsif ( $current_input_type == $INPUT_TYPE{ARGS} ) {
  55. $input = join ' ', @ARGV;
  56. }
  57. elsif ( $current_input_type == $INPUT_TYPE{STDIN} ) {
  58. # Slurp all STDIN at once, not line-by-line
  59. $input = $char . do { local $/; <STDIN> };
  60. }
  61. else {
  62. my $file = "a.out";
  63. open(my $ifh, '<', $file) or die "Can't open $file: $!";
  64. $input = do { local $/; <$ifh> };
  65. close($ifh) || warn "close failed: $!";
  66. }
  67. return $input;
  68. }
  69. my $input = multi_input();
  70. my $reversed = reverse $input;
  71. print "$input\n";
  72. print "$reversed\n";

Sunday, April 26, 2015

Please ignore, just testing styles

The Comments Section of a Blog is Important

Some people still don't read a blog's comments. I encourage you to do so if the topic interests you. The original post is not complete without the comments, because in them you will often find corrections to the original post or suggestions that improve upon it.  Sometimes you will read comments that you feel add little, or, if it's especially popular (not mine), flame wars and maybe some spam. But it's better to have the conversation than a lone blog post with a single person's opinions and experiences.

I have been tempted in the past to update my own posts with valuable input from the comment section, but I think it's better to encourage folks to read them. What's useful to me might not be useful to you.

There's no single person that knows everything I know, but for any given topic, there's someone who knows more about it than I do.  That's why the comments are important.

But don't take my word for it. Trust me on that. :)

Sunday, April 05, 2015

Saving Vertical Space

I was reviewing some code I had written for a simple RPG dice algorithm (although there's already a good module for this, Game::Dice) and I realized again that I have a prefererence for functions that can fit on one screen. One strategy is breaking up the code into smaller routines but I sometimes like to compact it vertically as much as possible first.

This function roll, given a string of "dice language," should return the results of such a dice roll. An example of this would be "3d10+1" to roll three 10-sided dice and then add 1, or "4d6b3" which says to roll four 6-sided dice and take the best three.

Here's the function before the refactor:

sub roll {
    my $input = shift;
    die unless $input =~ /d/;
    if ( $input =~ /(\d*)d(\d+)\s*(\D?)\s*(\d*)/ ) {
        my $num   = $1 || 1;
        my $die   = $2;
        my $plus  = $3;
        my $end   = $4;
        my $total = 0;
        my @dice;
        for my $count ( 1 .. $num ) {
            my $single = int( rand($die) ) + 1;
            push @dice, $single;
            print "$single\n";
        }
        if ( $plus eq 'b' ) {
            if ( $end > $num ) {
                $end = $num;
            }
            @dice = sort { $b <=> $a } @dice;
            $#dice = $end - 1;
        }
        for my $die (@dice) {
            $total += $die;
        }
        if ( $plus eq '+' ) {
            $total += $end;
        }
        elsif ( $plus eq '-' ) {
            $total -= $end;
        }
        elsif ( $plus eq '*' ) {
            $total *= $end;
        }
        elsif ( $plus eq '/' ) {
            $total /= $end;
        }
        return $total;
    }
    return;
}

The first thing I did is to delete the first of this pair of lines, which was redundant, because the line that follows also checks the format of the input:

die unless $input =~ /d/;
if ( $input =~ /(\d*)d(\d+)\s*(\D?)\s*(\d*)/ ) {

But instead of having that big if block, I changed it to this:

return unless $input =~ /(\d*)d(\d+)\s*(\D?)\s*(\d*)/;

Then I combined these:

my $die   = $2;
my $plus  = $3;
my $end   = $4;

into this:

my ($die,$plus,$end) = ($2,$3,$4);

Once I decided I didn't need to print each individual die as it was rolled, I could reduce this:

for my $count ( 1 .. $num ) {
    my $single = int( rand($die) ) + 1;
    push @dice, $single;
    print "$single\n";
}

to this:

push @dice, int(rand($die))+1 for ( 1..$num );

Then, I changed this:

if ( $end > $num ) {
    $end = $num;
}

To use the postfix if:

$end =  $num if $end > $num;

and this:

for my $die (@dice) {
    $total += $die;
}

to use postfix for:

$total += $_ for @dice;

One thing I like to do with an if/else chain like this:

if ( $plus eq '+' ) {
    $total += $end;
}
elsif ( $plus eq '-' ) {
    $total -= $end;
}
elsif ( $plus eq '*' ) {
    $total *= $end;
}
elsif ( $plus eq '/' ) {
    $total /= $end;
}

is to compress it like this:

if    ( $plus eq '+' ) { $total += $end }
elsif ( $plus eq '-' ) { $total -= $end }
elsif ( $plus eq '*' ) { $total *= $end }
elsif ( $plus eq '/' ) { $total /= $end }

Since it's still short in width and the syntax can lined up to be quite readable.

So the final version of the refactored function is:

sub roll {
    my $input = shift;
    return unless $input =~ /(\d*)d(\d+)\s*(\D?)\s*(\d*)/;
    my $num = $1 || 1;
    my ($die,$plus,$end) = ($2,$3,$4);
    my $total = 0;
    my @dice;
    push @dice, int(rand($die))+1 for ( 1..$num );
    if ( $plus eq 'b' ) {
        $end =  $num if $end > $num;
        @dice = sort { $b <=> $a } @dice;
        $#dice = $end-1;
    }
    $total += $_ for @dice;
    if    ( $plus eq '+' ) { $total += $end }
    elsif ( $plus eq '-' ) { $total -= $end }
    elsif ( $plus eq '*' ) { $total *= $end }
    elsif ( $plus eq '/' ) { $total /= $end }
    return $total;
}

Now you can make things a lot smaller (see Perl Golf examples) but readability is important to me, and I think this is arguably as readable as the original. I was actually a little surprised that perltidy barely touched the if/elsif structure, just screwing up the alignment a little on the first line:

if ( $plus eq '+' ) { $total += $end }
elsif ( $plus eq '-' ) { $total -= $end }
elsif ( $plus eq '*' ) { $total *= $end }
elsif ( $plus eq '/' ) { $total /= $end }

The code doesn't strictly adhere to Perl Best Practices, which is something I like to use as a guide for the most part, but perlcritic (which is based on Perl Best Practices) doesn't start to complain until the cruel setting, then bringing up things like postfix if, postfix for, and unless.

How would you make it smaller while still maintaining readability?