Kyle R. Burton on 28 Aug 2007 01:49:25 -0000


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[philly-lambda] Pattern or Antipattern?

  • From: "Kyle R. Burton" <kyle.burton@gmail.com>
  • To: philly-lambda@googlegroups.com
  • Subject: [philly-lambda] Pattern or Antipattern?
  • Date: Mon, 27 Aug 2007 21:49:09 -0400
  • Authentication-results: mx.google.com; spf=pass (google.com: domain of kyle.burton@gmail.com designates 209.85.132.242 as permitted sender) smtp.mail=kyle.burton@gmail.com; dkim=pass (test mode) header.i=@gmail.com
  • Dkim-signature: a=rsa-sha1; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:to:subject:mime-version:content-type; b=nVBBLd8R6hDv36hKzX6WaJt7Hwic8Zix+dS3VkrJNUyryWNyg/yFzC9enmDS5ZwJIP0o/lBGmVf01hcw73UO2Wr6/EwYqEmJvpuPINfJd40DCVwLX3bIphD7CthrYXoJO8wYDIZJ5bBF+vFej74R1WjtOzaKo8mt89sbBSJ86wU=
  • Mailing-list: list philly-lambda@googlegroups.com; contact philly-lambda-owner@googlegroups.com
  • Reply-to: philly-lambda@googlegroups.com
  • Sender: philly-lambda@googlegroups.com

While working with one of my developers (in Perl) we were discussing code patterns and I saw the "construct, configure and return instance" pattern and quickly wrote out what I'm used to using for that pattern (at least in Scheme), prog1:

sub aprog1 {
  my(@subs) = @_;
  sub {
    my $first = shift(@subs);
    my $it = ref($first) && 'CODE' eq ref($first) ? $first->() : $first;
    $_->($it) for @subs;
    return $it;
  };
}

my $person = aprog1(Foo->new,
                    sub {
                      my $it = shift;
                      $it->learnDance($_) for qw(boogie samba tango);
                    },
                    sub {Log("Made a new foo: ",shift->toString)})->();
}

Not idiomatic Perl, but it showed the pattern. Then a bit later we were debugging our application and arrived at some code with a chained conditional that wasn't (expectedly) passing its unit test:

sub canTheyDance {
  my($person) = @_;
         $person->knowsDance('boogie')
      && $person->knowsDance('chicken')
      && $person->knowsDance('tango');
}

We were trying to figure out how far through this conditional the code had made it. We were not inside the person module at the time, and it wasn't convenient to go and instrument it with logging. In a bit of twisted inspiration I saw a usage for prog1:

sub canTheyDance {
  my($person) = @_;
                                           prog1(1,sub {Log "before boogie test"})->() &&
         $person->knowsDance('boogie')  && prog1(1,sub {Log "after boogie, before chicken test"})->()
      && $person->knowsDance('chicken') && prog1(1,sub {Log "after chicken, before tango test"})->()
      && $person->knowsDance('tango')   && prog1(1,sub {Log "after tango (final)"})->();
}

Again, not idiomatic Perl, but it allowed us to see how far the conditional had gotten without having to go into the person module. We also didn't have rewrite the method into a bunch of discrete test/log statements. Using Emacs rectangle mode (or Vim's block mode) it was even easy to remove once we were done.

In Scheme/Lisp (where I picked up that form from), it would have looked more like this:

(define (can-they-dance person)
  (and (knows-dance person 'boogie)
       (knows-dance person 'chicken)
       (knows-dance person 'tango)))

And instead of interspersing with the prog1/log statements, I probably would have redefined and:

(define-macro (logging-and . rest)
  `(and ,@(map
             (lambda (condition)
                `(begin
                   (log "about to try: " ',condition)
                   ,condition)))))

(define (can-they-dance person)
  (logging-and (knows-dance person 'boogie)
               (knows-dance person 'chicken)
               (knows-dance person 'tango)))

In Java we probably would have unrolled the conditional into Christmas tree code:

  public boolean canTheyDance ( Person person ) {
    Log.debug("about to do boogie test");

    if ( !person->knowsDance("boogie") ) {
      Log.debug("failed boogie test");
      return false;
    }

    if ( !person->knowsDance("chicken") ) {
      Log.debug("failed chicken test");
      return false;
    }

    if ( !person->knowsDance("tango") ) {
      Log.debug("failed tango test");
      return false;
    }

    Log.debug("passed all tests, they can dance");
    return true;
  }

What was a pattern for the Perl code turned out to be anti-pattern for me in Scheme.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Philly Lambda" group.
To unsubscribe from this group, send email to philly-lambda-unsubscribe@googlegroups.com
For more options, visit this group at http://groups.google.com/group/philly-lambda?hl=en
-~----------~----~----~----~------~----~------~--~---