Dangling Definitions

Not sure why, but I hate this:

my $foo;

I like the advice define variables where you use them and have extended that to define variables when you create them, Defining variables as you bring them into existence is clean and self documenting and has the nice advantage of never (hopefully) creating an undef where none was intended. Careful programming can avoid that too!

However, I'm interested in comments regarding this construction (presented in pseudo-code):

my $foo  = do {
  if ( some-conditional ) { 
    ...
    value;
  }
  else {
   ...
    value;
  }
};

Essentially, this is a ternary operation.

( some-conditional ) ? value : value;

However, when the alternates are the result of multiple statements, using the ternary operator is at best forced and at worst down right misused (IMHO).

So...question to perl stylists...is the do { } closure too hinky simply to rid my code of Dangling Definitions?

8 Comments

Properly formatted ternary statements have the advantages of being quickly scannable, and unlikely to grow warts.


my $var =
    some-condition ? value1 :
    other-condition ? value2 :
    default-value;

my $var = some-condition
   ? value1
    : other-condition
        ? value2
        : default-value;

My key thought about the ternary is that you've got to play with the formatting until it doesn't look like a hack. I'll use it for lightly nested assignments and the rare return-wantarray?-foo-or:-bar.

An alternative to your do-block is to use an anonymous subroutine. This makes it petty easy to see the value that you're yielding back to the assignment:


my $var = sub {
    return value1 if some-condition;
    return value2 if other-condition;
    return default-value;
}->();

Like the do { ... } syntax, the sub { ... }->() does allow you to add weird extra logic in the middle of your variable assignment.

I think that at the point you're hoisting your initial value into a do BLOCK or an executed closure, that you may as well put a name on that bit of code:


my $var = get_initial_var;

Given some more meaningful name than get_initial_var() - a name that encapsulates the conditions being tested, which is hard to do with contrived examples! - you end up with highly self-documenting code.

While I agree in general, there are exceptions to this. Sometimes you need to declare a variable before its definition for scoping purposes. For example...

sub get_all_results_from_iterator
{
  my $iter = shift;
  my @results; # hanging definition
  
  if (blessed($iter) and $iter->isa('DBI::st')) {
    while (my $row = $iter->fetchrow_hashref) {
      push @results, $row;
    }
  }
  else {
    while (my $row = $iter->()) {
      push @results, $row;
    }
  }
  
  return @results;
}

I don't fancy the term 'dangling definition'. Perhaps 'declaration without initial value' is better (albeit more boring)?

And there are certainly cases where I want to declare a variable and let undef be its initial value.

my $found_value;
for (...) {
    if (some condition) {
        $found_value = blah;
        last;
    }
}
warn "Not found" unless defined($found_value);

and so on.

I'll admit my example is not the best there, but I do think doing 'my $foo = undef;' is redundant.

What gain does it give you? Especially since you said that you do not want to use the 'undef' value and want to reserve it to signal something's wrong/incomplete.

What gain does it give me? Since I always mean 'my $foo' to be 'my $foo = undef' in my code.

BTW, if you reserve 'undef' to mean something's incomplete, how would you deal with getting undef from somewhere else (like return value from function) which means something fails, but not incomplete. Because the latter semantic is quite common in the Perl ecosystem.

The Perl 6 version of do/if is more natural:


$x = do { if ($a) { $b } else { $c } };  # Perl 5

$x = do if $a { $b } else { $c };        # Perl 6

The difference is that do can take a statement instead of a block and the condition to the if statement doesn't require parens, which together makes for more readable code.

Leave a comment

About rlauer

user-pic I blog about Perl.