in reply to undef==defined sometimes?

defined is not meant to be used on an array. For starters, it would be impossible for an array to be undefined since undef is a scalar value.

As such, it appears that defined imposes a scalar context on its argument. An array name in scalar context is the number of elements in that array. Numbers are defined, so defined(@bar) always returns true.

Furthermore, my @bar = undef; doesn't create an empty array. It creates an array with one element in it (undef). my @bar = (); and my @bar; are equivalent and create empty arrays.

If you want to check if the array is empty, just use the array name in scalar context:

my @bar = undef; print("There are ", scalar(@bar), " elements in \@bar\n"); print("\@bar is empty\n") if !@bar; print("\@bar isn't empty\n") if @bar; my @foo; print("There are ", scalar(@foo), " elements in \@foo\n"); print("\@foo is empty\n") if !@foo; print("\@foo isn't empty\n") if @foo;
There are 1 elements in @bar @bar isn't empty There are 0 elements in @foo @foo is empty

You can check if an *array element* is defined, since array elements are scalars.

my @bar = (undef, 'a'); print(defined($bar[0])?1:0, "\n"); # 0 print(defined($bar[1])?1:0, "\n"); # 1 print(defined($bar[2])?1:0, "\n"); # 0 (doesn't exist)

Update: Clarified some details
Update: "Deleted" a paragraph in response to ysth's reply.

Replies are listed 'Best First'.
Re^2: undef==defined sometimes? (body question)
by ysth (Canon) on May 03, 2008 at 00:44 UTC
    As such, it appears that defined imposes a scalar context on its argument. An array name in scalar context is the number of elements in that array. Numbers are defined, so defined(@bar) always returns true.
    Nope. defined() on arrays or hashes is special; it returns whether they've ever had storage allocated for elements. But because this has historically been misused (as in the OPs case), this behavior was deprecated in 5.6.0, and Linda should have seen a deprecated warning. See defined.
Re^2: undef==defined sometimes? (body question)
by perl-diddler (Chaplain) on May 03, 2008 at 00:07 UTC
    So, if I have a function that returns undef on error, else an array with results, I should assign it to a scalar and and see if it is undef, if not, then hope it's a reference to an array?

    If I'm "in" the function, and I return an array to a scalar won't perl coerce the array into a scalar length and assign that to my scaler instead? So I'll end up with either the number of elements in the array, or 'unef', but not the array?

    Seems like this is pushing me in the direction of not being able to return an array with a list of found values or 'undef' ... I think I 'resent' the syntax that @a=1, is an assignment to $a[0]...I can understand why it happens, but I'm not sure how useful it is given that by using the "@" and no index, I'm only wanting an array to be assigned. It seems a perversity to coerce undef into a defined array with value undef in the first element....

    Under what situations is this commonly useful? Or are there too many to number? Sigh. ...

    If I want to return 'undef' and have it be interpreted as an undef array, then I need to return ()....a bit of a pain, since I wanted higher level routines to not care about the type of a return unless they needed to use it, with undef always being 'undef'.....

    Just seems to complicate matters a bit.

      Seems like this is pushing me in the direction of not being able to return an array with a list of found values or 'undef' ...
      Right, because it's perfectly valid to return a list with the single value 'undef', and that's indistinguishable from a sub returning 'undef' as meaning 'nothing to return'.
      I think I 'resent' the syntax that @a=1, is an assignment to $a[0]...I can understand why it happens, but I'm not sure how useful it is given that by using the "@" and no index, I'm only wanting an array to be assigned. It seems a perversity to coerce undef into a defined array with value undef in the first element...
      @a=1 is indeed an array operation; it clears any current content in the whole array before assigning to $a[0].

      You'd suffer less confusion if you ditch the idea of "array" being a type of value. Values in perl are either lists or scalars; "array" is a variable type that can store a list (as is "hash", but in a different way).

      I think I 'resent' the syntax that @a=1, is an assignment to $a[0]...

      Why would you resent that and not resent that @a = (1, 2, 3) is an assignment to $a[0], $a[1], and $a[2], respectively? (Don't make the mistake that the parentheses have anything to do with list creation; they only exist for grouping, as the precedence of the assignment operator is higher than that of the comma operator.)

        chromatic, please tell merlyn to incorporate this post into the next Learning Perl ed. (where he says to do @empty = () instead of @not_empty = undef as it would have clarified this concept much sooner for me as well. The info is there but not specifically for this point.

      So, if I have a function that returns undef on error, else an array with results, I should assign it to a scalar and and see if it is undef, if not, then hope it's a reference to an array?

      Functions can *only* return lists of scalars. That list can contain 0, 1 or more scalars. One way to address your problem is to return an empty list (a list with no elements) on error, but that only works if returning an empty list never occurs on success.

      sub func { my ($error) = @_; my @results = ('some', 'values'); # 1 or more values. $error ? () : @results; } for (0..1) { my @results = func($_); print(@results ? "no error (@results)" : 'error', "\n"); }

      Another way is to always return exactly one scalar: undef on error or an array reference on success.

      sub func { my ($error) = @_; my @results = (); # 0 or more values. $error ? undef : \@results; } for (0..1) { my $results = func($_); print($results ? "no error (@$results)" : 'error', "\n"); }

      Why don't you just return nothing at all on error, and get over the non-problem problem?

      There was really no point in writing code here in hindsight. So ...

        Well -- I could, but then the calling function would get garbage if I used it in an assignment.

        The function was *supposed* to return a list and only returned undef as an error condition (which wasn't the same as returning an empty list). The undef was reserved for 'illegal operations', like an attempt to compare two strings where one string was undefined. Otherwise, if nothing was found, but no error occurred, it returned a list of size 0 ("()").

        If I didn't explicitly return a value, wouldn't the results of whatever the last calculation be returned, essentially returning "left-overs" by accident? I'd rather return 'undef' and have consistently wrong behavior rather than random behavior -- at least if it is consistently wrong, I'm more likely to notice a problem. :-)

        -l