in reply to (tye)Re: Replacement for defined(%)/defined(@)?
in thread Replacement for defined(%)/defined(@)?

I guess the question starts to boil down to is:

Does the so-called empty set (or hash) exist in Perl, and if so, is it possible to distiquish it from the undef case?

Let me back up and go back to my problem from last night. I'm writing test cases for Tie::Hash::Stack, and in the creation set, I want to make sure that the hash was actually tied, as it's possible to send a parameter that breaks the function (normally the function would catch and die at that point, but for test cases, I want to catch that problem). So I used something similar to this (yes, I know defined is wrong here, but stay with me...):

my %hash; tie( %hash, "Tie::Hash::Stack" ); print defined( %hash ) ? "ok" : "not ok";
Now, the object that I create with T:H:S is an array of hashes, and upon creation, an empty hash is pushed onto the array (e.g.: "( {} )" ). Thus, the hash may be empty, but it is certainly not undefined. Thus, this code:
my %hash; tie( %hash, "Tie::Hash::Stack" ); print ( %hash ) ? "ok" : "not ok";
fails to note the creation of the tie'd variable. At the time, I didn't know that tie returned anything that I could use to judge success or failure (note that the perlfunc:tie do not state anything about a return value, had to find that out for myself, which appears to be the object that the hash was tied to), but after I got to this problem, I eventually got to:
my %hash; my $obj = tie( %hash, "Tie::Hash::Stack" ); print defined( $obj ) ? "ok" : "not ok"; # or simply $obj ? "ok" : "not ok";
This works, there's no problems, so I can happily continue along wrt T:H:S.

But the underlying problem of the fact that an empty array or hash is undistinguisable from the undef case somewhat bothers me. The example code in my original post, for example, would require a change of logic as tye's pointed out in order to have the empty set and an error code separated. If I was really dealing with, on mathematical terms, of the empty set, I'd probably revert to some code like Functional.pm that gives me an object that acts like the empty set.


Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain

Replies are listed 'Best First'.
(tye)Re2: Replacement for defined(%)/defined(@)?
by tye (Sage) on Jun 29, 2001 at 23:41 UTC

    Let me expand a bit:

    sub undefined { return; } sub empty { my @array= (); return @array; } my @undefd; my @empty= (); my @dedefd= (1,2,3); @dedefd= undefined(); my @emptied= (1,2,3); @emptied= empty(); my @undef2= undefined(); my @empty2= empty(); print "\@undefd is defined\n" if defined @undefd; print "\@empty is defined\n" if defined @empty; print "\@dedefd is defined\n" if defined @dedefd; print "\@emptied is defined\n" if defined @emptied; print "\@undef2 is defined\n" if defined @undef2; print "\@empty2 is defined\n" if defined @empty2;
    yields just:
    @dedefd is defined @emptied is defined

    You can have an undefined array but there is no such things as an undefined list value. So you can't pass around arrays by value and successfully worry about whether they are defined or not. To make an array undefined, you have to write undef @array and to have a subroutine do that would require that a reference to the array be passed in.

    So you really shouldn't try to have two types of empty arrays/hashes. Unlike strings where there is the empty string and undef, Perl doesn't provide a special value for undefined arrays/hashes and doesn't make it easy for you to provide one of your own.

    If I need to distinguish an empty list from an error, then I'd probably return a reference to an empty array for the first case and a "false" value for the second.

            - tye (but my friends call me "Tye")
Re: Re: (tye)Re: Replacement for defined(%)/defined(@)?
by John M. Dlugosz (Monsignor) on Jun 29, 2001 at 23:35 UTC
    The "thing" called %hash exists. It may have nothing in it, but it never becomes something other than a hash.

    undef is a scalar concept. A scalar can be a number, a string, various other things, or undef which is a special =value= meaning none of the above. A hash doesn't hold a value -- it is a tree of values. Only individual hash elements can =hold= undef.

    If you are asking if %hash is in the symbol table at all, it is, since compiling the name %hash in that statement does it! So use the symbol-table hash ($main::{hash}, I think) to see if that's even in the table, but it won't tell you that there is no %hash specifically, but no $hash, @hash, etc. as well. Seeing if the HV in the glob is getting into guts, but look at Devel::Peek module to do that.

    Point is what you suspect: whether the hash has zero entries in the normal way, or whether the structure has not been allocated at all yet is an internal implementation detail, not visible to the language. Conceptually, the container always exists, though it may be empty. Just as a scalar =exists= but holds the value called undef, instead of 42. There is no special value for the container that fills an analogous role.

    —John