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
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.
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{$_}++;
@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"
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