What's the difference between "delete" and "undef" with hashes?

Hashes are pairs of scalars: the first is the key, the second is the value. The key will be coerced to a string, although the value can be any kind of scalar: string, number, or reference. If a key $key is present in the array, exists will return true. The value for a given key can be undef, in which case $array{$key} will be undef while $exists{$key} will return true. This corresponds to ($key, undef) being in the hash.

Pictures help... here's the %ary table:

	  keys  values
	+------+------+
	|  a   |  3   |
	|  x   |  7   |
	|  d   |  0   |
	|  e   |  2   |
	+------+------+

And these conditions hold

	$ary{'a'}                       is true
	$ary{'d'}                       is false
	defined $ary{'d'}               is true
	defined $ary{'a'}               is true
	exists $ary{'a'}                is true (perl5 only)
	grep ($_ eq 'a', keys %ary)     is true

If you now say

	undef $ary{'a'}

your table now reads:

	  keys  values
	+------+------+
	|  a   | undef|
	|  x   |  7   |
	|  d   |  0   |
	|  e   |  2   |
	+------+------+

and these conditions now hold; changes in caps:

	$ary{'a'}                       is FALSE
	$ary{'d'}                       is false
	defined $ary{'d'}               is true
	defined $ary{'a'}               is FALSE
	exists $ary{'a'}                is true (perl5 only)
	grep ($_ eq 'a', keys %ary)     is true

Notice the last two: you have an undef value, but a defined key!

Now, consider this:

	delete $ary{'a'}

your table now reads:

	  keys  values
	+------+------+
	|  x   |  7   |
	|  d   |  0   |
	|  e   |  2   |
	+------+------+

and these conditions now hold; changes in caps:

	$ary{'a'}                       is false
	$ary{'d'}                       is false
	defined $ary{'d'}               is true
	defined $ary{'a'}               is false
	exists $ary{'a'}                is FALSE (perl5 only)
	grep ($_ eq 'a', keys %ary)     is FALSE

See, the whole entry is gone!