Web Developer's Virtual Library: Encyclopedia of Web Design Tutorials, Articles and Discussions


WDVL Newsletter

Active Server Pages
JSP/Java Servlets
Microsoft SQL Server
Daily Backup
Dedicated Servers
Streaming Audio/Video
24-hour Support    

jobs.webdeveloper.com

Hiermenus


e-commerce
Partner With Us















Developer Channel
FlashKit.com
JavaScript.com
JavaScriptSource
Developer Jobs
ScriptSearch
StreamingMediaWorld
Web Developer's Journal
Web Developer's Virtual Library
WebDeveloper.com
Webreference
Web Hosts
XMLfiles.com

internet.com
IT
Developer
Internet News
Small Business
Personal Technology

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers


Returning the Undefined Value - Page 20

July 27, 2001

Although it might seem a strange idea, it is quite common for subroutines and many of Perl's built-in functions to return the undefined value undef instead of a real (that is, defined) value.

The advantage of undef is that it evaluates to 'False' in conditions, but is distinct from a simple zero because it returns False when given as an argument to defined. This makes it ideal for use in subroutines that want to distinguish a failed call from one that just happens to return no results. This modified version of list_files uses undef to flag the caller when no path is specified:

#!/usr/bin/perl
# findfiles.pl
use warnings;
use strict;
my $files = list_files ($ARGV[0]);

if (defined $files) {
  if ($files) {
    print "Found: $files \n";
  } else {
    print "No files found \n";
  }
} else {
print "No path specified\n";
}


sub list_files {
  my $path = shift;

  return undef unless defined $path;
  # return an empty list if no path
  return join(',', glob "$path/*");
  # return comma separated string
}

If no path is supplied, the subroutine returns undef, which evaluates to False in the if statement. If the path was supplied but no files were found, the subroutine returns an empty string which would evaluate to False on its own but is still defined and so tests True in the if statement. We then test the value of $files with the ternary operator and print out an appropriate message if the string happens to be empty. Note that in this particular application checking @ARGV first would be the correct way to handle a lack of input, but we are concerned with the subroutine here, which cannot know how, where, or why it is being called.

undef works well in a scalar context, but is not so good for lists. While it is perfectly possible to assign undef to an array variable, it is confusing because what we end up with is an array of one value, which is undefined. If we naively tried to convert our subroutine to return a list instead of a scalar string we might write:

sub list_files {
  my $path = shift;

  return undef unless defined $path; # return undef if no path
  return glob "$path/*"; # return a list of files
}

Unfortunately if we try to call this function in a list context, and do not specify a defined path, we end up with anomalous behavior:

foreach (list_files $ARGV[0]) {
  print "Found: $_\n";
  # $_  == undef if path was not defined
}

If the path is undefined this will execute the loop once, print 'Found: ' and generate an uninitialized value warning. The reason for this is that undef is not a list value, so when evaluated in the list context of the foreach loop, it is converted into a list containing one value, which happens to be undefined. As a result, when the subroutine is called with an undefined path the loop executes once, with the value of the loop variable $_ being undefined.

In order for the loop to behave the way we intended, and not execute even once when no results are found, we need to return an empty list. Here's another version of list_files that does this:

sub list_files {
  my $path = shift;
  return () unless defined $path; # return empty list if no path
  return glob "$path/*"; # return list of files.
}

This fixes the problem we had when returning undef, but at the cost of losing the ability to distinguish between an undefined path and a path that happens to contain no files. What we would really like to do is return either undef or the empty list depending on whether a scalar or list result is required. The wantarray function provides exactly this information, and we cover it next.

Returning Values from Subroutines - Page 19
Professional Perl Programming
Determining and Responding to the Calling Context - Page 21


Up to => Home / Authoring / Languages / Perl / ProPerl




Jupiter Online Media: internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and Jupiter Online Media

Jupitermedia Corporate Info


Legal Notices, Licensing, & Permissions, Privacy Policy.

Web Hosting | Newsletters | Tech Jobs | Shopping | E-mail Offers