On 12/17/05, Darren Duncan <[EMAIL PROTECTED]> wrote:
> An undefined value is NOT the same as zero or an empty string
> respectively; the latter two are very specific and defined values,
> just like 7 or 'foo'.

I definitely agree with you in principle.  This is something that has
been bugging me, too.  However, there are some holes in your argument
and proposal, so I'll poke at them.

> Undef, by definition, is different from and non-equal to everything
> else, both any defined value, and other undefs.

You said "by definition", but where is this definition?

> 1. Any expression that expects a defined value as an argument, such
> as typical mathematical or string operations, and gets an undefined
> argument, will as a whole have undef as its value, or it will fail.
> Examples are the expressions "$anything + undef" and "$anything ~
> undef".

Hmm.  Maybe this has some relation to "use fatal".

> 2. Any boolean-returning expression should return undef or false or
> fail if given an undef.

So:

    undef == 3  # false
    undef != 3  # false!?

    undef < 3   # false
    undef > 3   # false
    undef == 3  # false!?

Failure seems to be the better option here.

However, I don't think that's a good option either.  When you say:

    if $x === "hello" {...}

You kinda want that just not to execute, because $x is not the same as "hello".

Your proposal is trying to make undef less magical.  Well, a good way
to do that would be to make it less magical; i.e. simply make it a
singleton value (it has class Undef, and the only thing that can be of
class Undef is undef).  Therefore:

    3 + undef   # fails because infix:<+>(Int, Undef) isn't defined

> 2a. At the very least, "undef <equality-test-op> undef" should NEVER
> return true, because an unknown quantity can not be claimed to be
> equal to an unknown quantity.  Rather, the defined() method, which is
> analagous to 'IS NOT NULL', and such things are the proper way to
> test if a variable is unknown.

  undef == 3     # fails (undef is not a number, so it can't be compared to one)
  undef eq "foo" # fails (undef is not a string)
  undef === 3    # false (the undef object is not the same as the 3 object)

> 2b. As a pseudo-exception, while undef/unknown values are
> conceptually all unequal to each other, they should all sort
> together; eg, calling sort() on an array of values where some are
> defined and some not, should group all the undefs together.  I leave
> it up to discussion as to whether they should sort before or after
> all the defined values, but one of those choices should be picked for
> predictability.

You're actually saying that undef either compares less than or greater
than all other objects, which contradicts your earlier point.  I'd say
it just fails.

> 5. In any situation where a developer wants an undefined value to
> become a zero or empty string or something else, they should say so
> explicitly, such as with:
>
>   $foo = undef // 0;
>   $bar = undef // '';
>   $baz = undef // $MY_DEFAULT;
>
> The fact is, that in any normal program, using an undefined value as
> if it were a defined one is a bug.  Normally there will be a point
> where such a variable should be tested for definedness and either be
> given a default value explicitly or fail.  Checking your input at the
> gates is good programming practice.

But checking input at the gates is also something you'd like to happen
automatically, or declaratively at the very least.  Thus all of Perl
6's type signature nonsense.

And you're also losing a rather important idiom:

    my %seen;
    my @q = ($initial);
    for @q {
        next if $seen{$_}++;
        @q.push(.next_nodes);
    }

You are also losing autovivification, which is one of Perl's staples.

Actually, you can think of undef pretty much as defining
autovivification.  "If you use it as a number, it becomes a number; if
you use it as a string, it becomes a string; if you use it as a hash,
it becomes a hash; ..."

However, that's not really accurate, because:

    # perl 5
    my $x;
    $x->{4} = 1;
    print $x;   # "HASH(...)"

    my $x;
    my $y = $x + 1;
    print $x;   # not "0"

While the premise of this proposal is nice, it feels like it's missing
the big picture.  Undef is what subs use when they fail if the caller
is not under "use fatal".  However, people have been requesting this
sort of dwimmery:

    open "foo" err die "Hey, I couldn't open it";
    open "foo";  # dies if it fails anyway

It would be nice to see a proposal of undef that handles this sort of
thing cleanly (saying "if a sub returns undef at the top statement
level without being handled then it throws an error" is not clean).

I guess what I'm saying is that it would be cool to make undefs and
exceptions the same thing, and to do away with "use fatal".  That may
be an impossible hope.

Luke

Reply via email to