At 9:30 AM +0000 12/17/05, Luke Palmer wrote:
On 12/17/05, Darren Duncan <[EMAIL PROTECTED]> wrote:
 > 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?

Maybe "definition" was the wrong word; I meant "by reasonable assumption" partly.

And also, since I consider undef and SQL's null to mean the same thing, which is "I don't know what the value is that should go here", SQL does explicitly define NULL to be unequal to all other values and NULLs, which seems a fine precedent.

 > 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

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.

At the time I wrote this, I had been thinking that having a list of array values where some were undefined was still not unreasonable to be sorted. And in that case, since undef's can't sort by normal means (value comparisons don't work on them), we have to do something with them so the sorted array has all the elements of the original, hence group them at one end.

However, perhaps it does make better sense for wider consistency that a sort needs to have an explicit handler that says what to do with undefs, or otherwise the sort 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.

Yes, and I'm not proposing we change that. However, unless Pugs' implementation is wrong, the declaritive signitures only check that subs get the right number of arguments and that each one is of the correct container type. Whether or not an argument has a ? in the declaration only toggles whether a container needs to be passed to it, not what the container has in it. If someone provides an undefined value as an argument, that is let through, since it could be valid input for some subs. Those subs for which an undef is invalid currently need to either put an explicit "where { .defined }" trait on their argument or use a //= etc on it inside the called sub. Now maybe this behaviour is wrong, but its what I observed.

And you're also losing a rather important idiom:

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

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"

Actually, I don't like autovivification either, and wish there was a pragma to make attempts to do it a fatal error; it smacks too much of using variables that weren't declared with 'my' etc. I prefer to put in the explicit "$seen{$_} //= 0;" above the ++ line, and "$x = hash()" in as well, etc.

This behaviour is more consistent with what is expected if, say, you have some random other class being used instead of a hash or array, which don't support the same autovivification behaviour. If you tried calling "$seen{$_}->inc()", it would die, not turn into a counter object and then increment.

I forget if I mentioned autovivification on this list before, but now I have.

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).

That's not a problem. I believe err() is defined such that 'undef' is a valid argument option, in which case it has no reason to die. So with my proposal enacted, this would still work fine.

Its just things like the + and ~ operators that shouldn't accept undef args, but many other operators such as err() can take undef.

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.

If you do that, it would get away from the meaning of undef I had in mind.

You see, I see that returning "undef" on failure is saying "while you expected me to return something, I failed and can't return any actual value".

This said, if returning undef always caused an exception, I question what would happen with procedures that return nothing because they're not supposed to.

-- Darren Duncan

Reply via email to